package com.cellulam.framework.push.sms;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.regions.ProductDomain;
import com.cellulam.framework.core.auth.UserBasicInfo;
import com.cellulam.framework.core.auth.UserClient;
import com.cellulam.framework.core.exceptions.SysException;
import com.cellulam.framework.core.spring.SmartEnvironment;
import com.cellulam.framework.core.utils.JacksonUtils;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Set;
import java.util.concurrent.CompletableFuture;

@Slf4j
public class SmsSender {
    private static final String DEFAULT_SMS_DOMAIN = "dysmsapi.aliyuncs.com";
    private static final String DEFAULT_SMS_PRODUCT = "Dysmsapi";
    private static final String ACTION_SEND_SMS = "SendSms";

    private IAcsClient client;
    private String smsDomain;
    private String defaultSignName;
    private UserClient userClient;
    private String product;
    private String defaultSource;

    public SmsSender() {
        this(null);
    }

    public SmsSender(UserClient userClient) {
        String regionId = SmartEnvironment.env.getProperty("ali.region-id");
        String accessKeyId = SmartEnvironment.env.getProperty("ali.access-key");
        String accessSecret = SmartEnvironment.env.getProperty("ali.access-secret");

        this.defaultSignName = SmartEnvironment.env.getProperty("ali.sms.default-sign-name");
        this.defaultSource = SmartEnvironment.env.getProperty("spring.application.name", "");
        this.smsDomain = SmartEnvironment.env.getProperty("ali.sms.api.domain", DEFAULT_SMS_DOMAIN);
        this.product = SmartEnvironment.env.getProperty("ali.sms.api.product", DEFAULT_SMS_PRODUCT);

        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessSecret);
        this.client = new DefaultAcsClient(profile);
        this.userClient = userClient;
    }

    private <T> void sendSync(SmsMessage<T> message) {

        String source = StringUtils.isEmpty(message.getSource()) ? defaultSource : message.getSource();

        String mobiles = this.extractMobiles(message);

        SendSmsRequest request = new SendSmsRequest();
        request.setProductDomain(new ProductDomain(this.product, this.smsDomain));
        request.setMethod(MethodType.POST);
        request.setActionName(ACTION_SEND_SMS);
        request.setPhoneNumbers(mobiles);
        request.setSignName(StringUtils.isEmpty(message.getSignName()) ? defaultSignName : message.getSignName());
        if (StringUtils.isEmpty(request.getSignName())) {
            throw new SysException("请配置短信签名");
        }
        request.setTemplateCode(message.getTemplateCode());
        String params = JacksonUtils.toJson(message.getParams());
        request.setTemplateParam(params);
        String outId = source + "$" + message.getResourceId().toString();
        request.setOutId(outId);

        try {
            SendSmsResponse response = this.client.getAcsResponse(request);

            log.info("发送短信完成, outId: {}, mobile: {}, template: {}, params: {}, response: {}",
                    outId,
                    mobiles,
                    message.getTemplateCode(),
                    params,
                    JacksonUtils.toJson(response));

            if (response == null || !response.getCode().equalsIgnoreCase("ok")) {
                throw new SysException("短信发送失败" + response == null ? "" : ": " + response.getMessage());
            }
        } catch (Exception e) {
            log.error("发送短信失败, mobile: {}, template: {}, params: {}, response: {}",
                    mobiles,
                    message.getTemplateCode(),
                    params,
                    e);
            throw new SysException(e);
        }
    }

    public <T> void send(SmsMessage<T> message) {
        if (message.isAsync()) {
            CompletableFuture.runAsync(() -> this.sendSync(message));
        } else {
            this.sendSync(message);
        }
    }

    private <T> String extractMobiles(SmsMessage<T> message) {
        Set<String> mobiles = Sets.newConcurrentHashSet();
        if (!CollectionUtils.isEmpty(message.getMobiles())) {
            message.getMobiles().forEach(x -> mobiles.add(x));
        }

        if (!CollectionUtils.isEmpty(message.getUserIds())) {
            if (userClient == null) {
                throw new UnsupportedOperationException("不支持用户ID");
            }

            message.getUserIds()
                    .parallelStream()
                    .forEach(x -> {
                        UserBasicInfo user = this.userClient.getUserById(x);
                        if (user == null) {
                            log.error("找不到用户: {}", x);
                            return;
                        }
                        if (StringUtils.isEmpty(user.getMobile())) {
                            log.error("用户没有手机号: {}", x);
                        }
                        mobiles.add(user.getMobile());
                    });
        }
        return String.join(",", mobiles);
    }
}
